package org.example;


import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.StrUtil;

import java.io.*;

public class cmd {
//1.使用Runtime中exec(String command)方法执行cmd命令，如下：
//    Process p = Runtime.getRuntime().exec(cmd);
//    此方法会抛出IOException，但是在项目中遇到没有出现异常，命令也没有执行的情况。
//2.此方法可以达到大多的cmd调用的期望结果，但有些时候回出现命令卡死在p.waitFor();上，造成线程阻塞，
// 原因：https://blog.csdn.net/weixin_34408624/article/details/86015882

    public static boolean runCMD(String cmd) throws IOException, InterruptedException {
        final String METHOD_NAME = "runCMD";
        Process p = Runtime.getRuntime().exec(cmd);
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
            String readLine = br.readLine();
            StringBuilder builder = new StringBuilder();
            while (readLine != null) {
                readLine = br.readLine();
                builder.append(readLine);
            }
            System.out.println(METHOD_NAME + "#readLine: " + builder.toString());

            p.waitFor();
            int i = p.exitValue();
            System.out.println(METHOD_NAME + "#exitValue = " + i);
            if (i == 0) {
                return true;
            } else {
                return false;
            }
        } catch (IOException e) {
            System.out.println(METHOD_NAME + "#ErrMsg=" + e.getMessage());
            e.printStackTrace();
            throw e;
        } finally {
            if (br != null) {
                br.close();
            }
        }
    }

    //    3.使用以下方法不会出现和2一样情况下得阻塞的问题，与2的区别就是获取流不同，将getErrorStream换成getInputStream就好了
    public static boolean runCMD3(String cmd) throws IOException, InterruptedException {
        final String METHOD_NAME = "runCMD";

        // Process p = Runtime.getRuntime().exec("cmd.exe /C " + cmd);
        Process p = Runtime.getRuntime().exec(cmd);
        BufferedReader br = null;
        try {
            // br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
            br = new BufferedReader(new InputStreamReader(p.getInputStream()));
            String readLine = br.readLine();
            StringBuilder builder = new StringBuilder();
            while (readLine != null) {
                readLine = br.readLine();
                builder.append(readLine);
            }
            System.out.println(METHOD_NAME + "#readLine: " + builder.toString());

            p.waitFor();
            int i = p.exitValue();
            System.out.println(METHOD_NAME + "#exitValue = " + i);
            if (i == 0) {
                return true;
            } else {
                return false;
            }
        } catch (IOException e) {
            System.out.println(METHOD_NAME + "#ErrMsg=" + e.getMessage());
            e.printStackTrace();
            throw e;
        } finally {
            if (br != null) {
                br.close();
            }
        }
    }

    // 4.对于3方法有个缺点是执行错误时无法将错误消息打印出来，还有一个方法是先将执行的cmd命令写入到文件中后再执行，这是如果执行错误日志可以打印，线程也不会卡死。
//
//            　　a.将执行的命名写入到文件中。FileUtils.java
    public static boolean writeFile(File exportFile, final String content) {
        if (exportFile == null || StrUtil.isEmpty(content)) {
            return false;
        }
        if (!exportFile.exists()) {
            try {
                exportFile.getParentFile().mkdirs();
                exportFile.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
                Console.error("create local json file exception: " + e.getMessage());
                return false;
            }
        }

        BufferedWriter bufferedWriter = null;
        try {
            FileOutputStream os = new FileOutputStream(exportFile);
            FileDescriptor fd = os.getFD();

            bufferedWriter = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
            bufferedWriter.write(content);

            //Flush the data from the streams and writes into system buffers
            //The data may or may not be written to disk.
            bufferedWriter.flush();

            //block until the system buffers have been written to disk.
            //After this method returns, the data is guaranteed to have
            //been written to disk.
            fd.sync();
        } catch (UnsupportedEncodingException e) {
            Console.error("saveDBData#catch an UnsupportedEncodingException (" + e.getMessage() + ")");
            return false;
        } catch (FileNotFoundException e) {
            Console.error("saveDBData#catch an FileNotFoundException (" + e.getMessage() + ")");
            return false;
        } catch (IOException e) {
            Console.error("saveDBData#catch an IOException (" + e.getMessage() + ")");
            return false;
        } catch (Exception e) {
            Console.error("saveDBData#catch an exception (" + e.getMessage() + ")");
            return false;
        } finally {
            try {
                if (bufferedWriter != null) {
                    bufferedWriter.close();
                    bufferedWriter = null;
                }
            } catch (IOException e) {
                Console.error("writeJsonToFile#catch an exception (" + e.getMessage() + ")");
            }
        }
        return true;
    }

    //    b.执行命令
    public static boolean excuteCMDBatFile(String cmd) {
        final String METHOD_NAME = "excuteCMDBatFile#";
        boolean result = true;
        Process p;
        File batFile = new File("D:/test/cmd.bat");
        System.out.println(batFile.getAbsolutePath());
        File file = FileUtil.writeUtf8String(cmd, batFile);
        //todo 判断写入文件成功
        if (!file.exists()) {
            Console.error(METHOD_NAME + "write cmd to File failed.");
            return false;
        }

        String batFilePath = "\"" + MigrateContants.CMD_BAT_FILE + "\"";
        Console.log("cmd path:" + batFilePath);
        try {
            p = Runtime.getRuntime().exec(batFilePath);
            InputStream fis = p.getErrorStream();//p.getInputStream();
            InputStreamReader isr = new InputStreamReader(fis, System.getProperty("file.encoding"));
            BufferedReader br = new BufferedReader(isr);
            String line = null;
            StringBuilder builder = new StringBuilder();
            while ((line = br.readLine()) != null) {
                builder.append(line);
            }

            p.waitFor();
            int i = p.exitValue();
            Console.log(METHOD_NAME + "exitValue = " + i);
            if (i != 0) {
                result = false;
                Console.error(METHOD_NAME + "excute cmd failed, [result = " + result + ", error message = " + builder.toString() + "]");
                System.out.println(METHOD_NAME + "excute cmd failed, [result = " + result + ", error message = " + builder.toString() + "]");
            } else {
                // logger.debug(METHOD_NAME + "excute cmd result = " + result);
                System.out.println(METHOD_NAME + "result = " + result);
            }
        } catch (Exception e) {
            result = false;
            e.printStackTrace();
            Console.error(METHOD_NAME + "fail to excute bat File [ErrMsg=" + e.getMessage() + "]");
        }

        return result;
    }
}
